/**
**************************************************************************************
*Founder Effect                                                                      *
*Copyright (C) 2006-2007, 5d Studios (www.5d-Studios.com)                            *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
#include "StdAfx.h"
#include <stdlib.h>
#include "Binder.h"
#include "../shared/StringUtil.h"
#include "../Kernel.h"

extern Kernel* g_kernel;

Binder::Binder(void)
{
    m_bindListCmd.Set( this );
    m_bindCmd.Set( this );
    m_unbindAllCmd.Set( this );
    m_unbindCmd.Set( this );

    if ( g_kernel )
    {
        g_kernel->GetConsole()->AddCommand( &m_bindListCmd, "bindlist" );
        g_kernel->GetConsole()->AddCommand( &m_bindCmd, "bind" );
        g_kernel->GetConsole()->AddCommand( &m_unbindAllCmd, "unbindall" );
        g_kernel->GetConsole()->AddCommand( &m_unbindCmd, "unbind" );
    }
}


/** Bind a key to an action */
void Binder::Bind( int key, const std::string &function)
{
    m_bindings[key] = function;
}
/** Unbind a key from an action */
void Binder::UnBind( int key )
{
    std::map<int, std::string >::iterator it = m_bindings.begin();
    for(; it != m_bindings.end(); it++ )
    {
        if ( it->first == key ) {
            m_bindings.erase( it );
            return;
        }
    }
}
/** Unbind all keys */
void Binder::UnBindAll()
{
    m_bindings.clear();
}
/** Execute the key bind, if any */
void Binder::Exec( int key )
{
    // first test to see if it is a valid bind
    if ( m_bindings.find( key ) != m_bindings.end() )
    {
        if ( g_kernel )
            // exec the string
            g_kernel->GetConsole()->Exec( m_bindings[key] );
    }
}

/** Print the binded commands */
void Binder::Print()
{
    g_kernel->Printf( "---------------Bind Report------------------" );
    KeyConverter converter;

    std::map<int, std::string >::iterator it = m_bindings.begin();
    for(; it != m_bindings.end(); it++ )
    {
        if ( g_kernel )
        {
            std::string str = converter.ToString( it->first ) + " is binded with ";
            g_kernel->Printf( ( str + it->second ).c_str() );
        }
    }
    g_kernel->Printf( "  %d Total binds", m_bindings.size() );
}


Binder::~Binder(void)
{
    if ( g_kernel )
    {
        g_kernel->GetConsole()->RemoveCommand( "bindlist" );
        g_kernel->GetConsole()->RemoveCommand( "bind" );
        g_kernel->GetConsole()->RemoveCommand( "unbindall" );
        g_kernel->GetConsole()->RemoveCommand( "unbind" );
    }
}




/**
============================================================================================
Bind function - bind a key to a console function
============================================================================================
*/
#include "KeyConverter.h"


// Bind_f :: Exec
/** Binds a key to a function */
void Binder::Bind_f::Exec(std::string &s) 
{
    std::string skey;
    KeyConverter convert;
    StringUtil token(s);
    
    // first check the first token
    if ( token.HasNext() ) {
        // the first token should be a key
        skey = token.GetNext();
        int key = convert.ToKeyCode( skey );
        
        // test to see if we have a cmd
        if ( token.HasNext() )
        {
            std::string cvar = token.GetNext();
            // test to see if the second token is a cvar
            if ( g_kernel->GetCvars()->IsValid( cvar ) )
            {
                int size = skey.length() + cvar.length();
                int length = s.length() - size;
                // if so, change its value
                g_kernel->GetCvars()->SetCvarValue( cvar, key );        
            } else if ( m_binder ) {
                // else it is a command
                m_binder->Bind( key, s.substr(skey.length(), s.length() - skey.length() ) );
            }
        } else {
            g_kernel->LPrintf( "<usage> bind [key] [action]" );
        }
    } 
    else
    {   // TODO - Print out all binds?
        g_kernel->LPrintf( "<usage> bind [key] [action]" );
    }
}


/**
==================================
Unbind a key
==================================
*/
void Binder::UnBind_f::Exec( std::string &s )
{
    if ( s == "" )
    {
        g_kernel->LPrintf( "<usage> unbind [key]" );
    } 
    else if ( m_binder )
    {
        KeyConverter convert;
        m_binder->UnBind( convert.ToKeyCode( s ) );
    }
}

/**
==================================
Unbind all keys
==================================
*/
void Binder::UnBindAll_f::Exec( std::string &s )
{
    if ( m_binder )
        m_binder->UnBindAll();
}
